package com.fzu.ess.sys.service.Impl;

import com.fzu.ess.common.Model.JsonModel;
import com.fzu.ess.common.Const;
import com.fzu.ess.common.service.MailService;
import com.fzu.ess.common.utils.SearchUtils;
import com.fzu.ess.ess.dao.ProfileDao;
import com.fzu.ess.ess.entity.Book;
import com.fzu.ess.ess.entity.Profile;
import com.fzu.ess.ess.service.ProfileService;
import com.fzu.ess.sys.dao.UserDao;
import com.fzu.ess.sys.entity.Role;
import com.fzu.ess.sys.entity.User;
import com.fzu.ess.sys.service.MessageService;
import com.fzu.ess.sys.service.RoleService;
import com.fzu.ess.sys.service.UserService;
import com.fzu.ess.sys.shiro.SpringCacheManagerWrapper;
import com.fzu.ess.sys.utils.RoleUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by ercha on 2015/10/16.
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Autowired
    private RoleService roleService;

    @Autowired
    private ProfileDao profileDao;

    @Autowired
    private ProfileService profileService;

    @Autowired
    private MailService mailService;

    @Autowired
    private MessageService messageService;

    private Cache<String, String> activeMailCache;

    @Autowired
    public UserServiceImpl(SpringCacheManagerWrapper shiroCacheManager){
        activeMailCache = shiroCacheManager.getCache(Const.CACHE_NAME.MAIL);
    }

    @Override
    public JsonModel login(String username, String password, Boolean rememberMe) {
        JsonModel jsonModel = new JsonModel();
        Subject subject = SecurityUtils.getSubject();

        //已经登录过则返回后台
        if(subject.isAuthenticated()){
            jsonModel.setSuccess(true);
            jsonModel.setMsg("/management");
            return jsonModel;
        }

        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        token.setRememberMe(rememberMe);
        try {
            subject.login(token);
            jsonModel.setSuccess(true);
            /** 将 User 对象放入 session */
            Session session = subject.getSession();
            session.setAttribute(Const.SESSION.USER, findByUsername(username));

            /** 将用户头像放入 session */
            /** 在这里将 avatar 转成符合 <img src=''> 的格式 */
            String avatar = profileService.get().getAvatar();
            if(avatar!=null && avatar.length()>1){
                avatar = "/images/@s" + avatar;
            }
            session.setAttribute(Const.SESSION.AVATAR, avatar);

            /** 将系统消息数放入 session */
            session.setAttribute(Const.SESSION.MESSAGE_CNT, messageService.unReadCnt());

            //SavedRequest savedRequest = WebUtils.getSavedRequest(request);
            //String redirectURI = savedRequest!=null ? savedRequest.getRequestURI() : null;
            //responseModel.setRedirectURI(redirectURI == null ? "/management" : redirectURI);
            jsonModel.setMsg("/management");
        } catch (UnknownAccountException unknownAccountException){
            jsonModel.setMsg("用户名/邮箱不存在");
        } catch (LockedAccountException lockedAccountException){
            jsonModel.setMsg("账号未激活");
        } catch (IncorrectCredentialsException ice){
            jsonModel.setMsg("用户名或密码错误！");
        } catch (ExcessiveAttemptsException eae) {
            jsonModel.setMsg("登录失败次数过多！请5分钟后再试！");
        } catch (AccountException ae){
            jsonModel.setMsg(ae.getMessage());
        }
        return jsonModel;
    }

    @Override
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        if(subject.isAuthenticated()){
            subject.logout();  // session 会销毁，在SessionListener监听session销毁，清理权限缓存
        }
    }

    @Override
    public User findByUsername(String username) {
        return userDao.get("from User u where u.username = '" + username + "' and u.delFlag = " + Const.DEL_FLAG_NORMAL);
    }

    @Override
    public User findByEmail(String email) {
        return userDao.get("from User u where u.email = '" + email + "' and u.delFlag = " + Const.DEL_FLAG_NORMAL);
    }

    @Override
    public User findByNameOrEmail(String nameOrEmail) {
        if(nameOrEmail.contains("@")){
            return findByEmail(nameOrEmail);
        }
        else return findByUsername(nameOrEmail);
    }

    @Override
    public List<User> getAllAdmin(){
        return userDao.find("from User u where u.level = " + Const.USER_LEVEL.ADMIN + " and u.delFlag = " + Const.DEL_FLAG_NORMAL);
    }

    @Override
    public String resetPassword(String email) {
        String newPassword = "";
        try {
            newPassword = (new Random().nextInt(1000000)) + 100000 + "";
            User user = findByEmail(email);
            if(user == null){
                return newPassword;
            }

            String enpwd = encryptByMd5(newPassword, user.getSalt(), user.getUsername());
            user.setPassword(enpwd);
//            System.out.println("enpwd" + enpwd);
            userDao.update(user);
        }catch (Exception e){
            e.printStackTrace();
        }
        return newPassword;
    }

    @Override
    public boolean confirmPassword(String password) {
        if(password==null || password.length()<1){
            return false;
        }
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        User user = (User)session.getAttribute(Const.SESSION.USER);

        password = encryptByMd5(password, user.getSalt(), user.getUsername());
        return user.getPassword().equals(password);
    }

    @Override
    public JsonModel updatePassword(String oldPassword, String password) {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        User user = (User)session.getAttribute(Const.SESSION.USER);

        JsonModel j = new JsonModel();
        oldPassword = encryptByMd5(oldPassword, user.getSalt(), user.getUsername());
        password = encryptByMd5(password, user.getSalt(), user.getUsername());

        if(!user.getPassword().equals(oldPassword)){
            j.setMsg("原密码错误！");
            return j;
        }

        user.setPassword(password);
        try {
            userDao.update(user);
            session.setAttribute(Const.SESSION.USER, user);
            j.setSuccess(true);
            return j;
        } catch (Exception e){
            e.printStackTrace();
            j.setMsg("更新失败，请稍后再试!");
            return j;
        }
    }

    @Override
    public JsonModel register(User user) {
        JsonModel jsonModel = new JsonModel();

        if(existUser(user)){
            jsonModel.setMsg("用户已存在！");
            return jsonModel;
        }

        encryptByMd5(user);
        //TODO: 未激活状态
//        user.setLevel(Const.USER_LEVEL.LOCKED);

        try {
//            List<Role> roleList = new ArrayList<>();
//            roleList.add(roleService.findById(Const.USER_LEVEL.LOCKED + ""));
//            user.setRoleList(roleList);
//        user.setStatus(Const.ACCOUNT_STATUS.UNACTIVATE);
            changeLevel(user, Const.USER_LEVEL.LOCKED);
            userDao.save(user);

            //创建个人信息
            Profile profile = new Profile();
            profile.setUser(user);
            profileDao.save(profile);

//            jsonModel.setMsg(Const.REGISTER_SUCCESS_URL);
            jsonModel.setSuccess(true);
        } catch(Exception e){
            e.printStackTrace();
//            jsonModel.setMsg(Const.REGISTER_FAILED_URL);
            jsonModel.setSuccess(false);
        }
        return jsonModel;
    }

    /**
     * 生成加密盐并对密码进行加密，密码已在 User 对象内
     * @param user
     */
    private void encryptByMd5(User user){
        int hashIterations = 2;
        user.setSalt((new SecureRandomNumberGenerator()).nextBytes().toHex());
        user.setPassword(new SimpleHash("md5", user.getPassword(), ByteSource.Util.bytes(user.getUsername()+user.getSalt()), hashIterations).toHex());
    }

    /**
     * 用于修改密码
     * @param password
     * @param salt
     * @param username
     * @return
     */
    private String encryptByMd5(String password, String salt, String username){
        int hashIterations = 2;
        return new SimpleHash("md5", password, ByteSource.Util.bytes(username+salt), hashIterations).toHex();
    }

    @Override
    public JsonModel activeUser(String uuid, String code) {
        String email = mailService.hasMail(uuid, code);

        JsonModel jsonModel = new JsonModel();

        if(email == null){
            jsonModel.setMsg("激活失败！无效的链接！");
            return jsonModel;
        }

        User user = findByEmail(email);
        if(user.getLevel() != Const.USER_LEVEL.LOCKED){
            jsonModel.setSuccess(true);
            jsonModel.setMsg("激活成功！");
            return jsonModel;
        }

        jsonModel.setSuccess(changeLevel(user, Const.USER_LEVEL.USER));
        return jsonModel;
    }

    @Override
    public JsonModel createAdmin(User admin) {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        User user = (User)session.getAttribute(Const.SESSION.USER);

        boolean res;

        JsonModel j = new JsonModel();
        if(!user.getLevel().equals(0)){
            j.setMsg("权限不足");
        }

        encryptByMd5(admin);
        changeLevel(admin, Const.USER_LEVEL.ADMIN);
        res = null != userDao.save(admin);

        if(!res){
            return j;
        }

        //创建个人信息
        Profile profile = new Profile();
        profile.setUser(admin);
        res = null != profileDao.save(profile);

        j.setSuccess(res);
        return j;
    }

    @Override
    public JsonModel adminPageData(Integer pageNumber, Integer pageSize, String filter) {
        JsonModel j = new JsonModel();

        StringBuilder hqlData = new StringBuilder("from User b where ");
        String hqlCount;

        if(filter!=null && filter.length()>1){
            hqlData.append(SearchUtils.getSearchStr(filter, "b"));
            hqlData.append(" and ");
        }

        hqlData.append(" b.level = " + Const.USER_LEVEL.ADMIN +  " and b.delFlag = " + Const.DEL_FLAG_NORMAL + " order by b.createDate desc ");

        if(pageNumber==null || pageNumber<0){
            pageNumber = 0;
        }

        if(pageSize==null || pageSize<0){
            pageSize = 0;
        }

        System.out.println("hql: " + hqlData.toString());
        hqlCount = "select count(*) " + hqlData.toString();
        try {
            List<User> bl = userDao.find(hqlData.toString(), pageNumber, pageSize);
            j.setDataObj(bl);
            j.setTotal(userDao.count(hqlCount));
            j.setRows(bl.size());
            return j;
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public JsonModel deleteAdmin(String id) {
        JsonModel j = new JsonModel();
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        User admin = (User)session.getAttribute(Const.SESSION.USER);

        if(admin.getLevel() != Const.USER_LEVEL.SUPER_ADMIN){
            return j;
        }
        try {
            int res;
            res = userDao.executeHql("update User b set b.delFlag = " + Const.DEL_FLAG_DELETED
                    + "where b.id = '" + id + "'");


            j.setSuccess(res > 0);
        } catch (Exception e){
            e.printStackTrace();
        }
        return j;
    }

    @Override
    public JsonModel resetAdminPassword(String id, String password) {
        JsonModel j = new JsonModel();
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        User superAdmin = (User)session.getAttribute(Const.SESSION.USER);
        if(superAdmin.getLevel() > Const.USER_LEVEL.SUPER_ADMIN || password==null || password.length()<1 || id==null || id.length()<1){
            return j;
        }

        User admin = findById(id);
        if(admin == null){
            return j;
        }

        password = encryptByMd5(password, admin.getSalt(), admin.getUsername());
        admin.setPassword(password);
        try {
            userDao.update(admin);
            j.setSuccess(true);
            return j;
        } catch (Exception e){
            e.printStackTrace();
            j.setMsg("重置失败，请稍后再试!");
            return j;
        }
    }

    private boolean existUser(User user){
        return findByUsername(user.getUsername())!=null || findByEmail(user.getEmail())!=null;
    }

    /**
     * 修改账户等级，同步更新角色
     * @param user
     * @param level
     * @return
     */
    private boolean changeLevel(User user, int level){
        Role role = roleService.findById(level + "");
        if(role==null){
            return false;
        }
        List<Role> roleList = new ArrayList<>();
        roleList.add(role);
        user.setRoleList(roleList);
        user.setLevel(level);
        return true;
    }

    private User findById(String id){
        return userDao.get("from User u where u.id = '" + id + "' and u.delFlag = " + Const.DEL_FLAG_NORMAL);
    }
}
